// 封装 axios
import { useUserStore } from '@/stores'
import axios, { type Method } from 'axios'
import router from '@/router'
import { showToast } from 'vant'

// 创建实例
const baseURL = 'https://consult-api.itheima.net/'
const instance = axios.create({
  // 定义基准路径
  baseURL,
  timeout: 5000
})

// 请求拦截器 (处理 token)
instance.interceptors.request.use((config) => {
  // 如果用户仓库数据中带有 token 注入到请求头中
  const store = useUserStore()
  if (store.user?.token && config.headers) {
    config.headers.Authorization = `Bearer ${store.user.token}`
  }

  // 最后一定是返回请求配置
  return config
})

// 响应拦截器 (处理错误)
// 可以接收两个参数, 一个处理响应码200, 一个处理其他硬性报错
instance.interceptors.response.use(
  (res) => {
    if (res.data.code === 10000) {
      // 数据正确
      return res.data
    } else {
      showToast(res.data.message || '系统错误')
      return Promise.reject(res.data)
    }
    // 请求成功, 数据也成功
    // 请求成功, 数据失败
    // todo 分开处理数据成功或者失败
  },
  (err) => {
    console.dir(err)
    // 硬性的错误
    // 要在错误处阻止当前 promise 的继续执行
    // todo 错误的可能给性很多, 特别要处理的是token失效(被动介入)
    // 根据测试(后台), token 如果出问题, 后台是会返回 401 报错
    if (err.response.status === 401) {
      // 清理用户数据
      const store = useUserStore()
      store.delUser()
      // 跳转登录，带上接口失效所在页面的地址，登录完成后回跳使用
      router.push({
        path: '/login',
        query: { returnUrl: router.currentRoute.value.fullPath }
      })
      // 跳回登录页
    }

    showToast(err.message)
    return Promise.reject(err)
  }
)

// 现在基本请求方式, 都是直接调用 instance, 然后每次传入 URL, method
// 又要自行判断method 是 get 还是post 来决定 带 params 还是 data参数
// 封装一个函数统一处理所有的请求, 希望只需要 request(url, method, data)
// const obj = {name: 'tom'}
// obj.name
// const str = 'name'
// obj[str]
type ResponseData<T> = {
  code: number
  message: string
  data: T
}
const request = <T>(
  url: string,
  method: Method = 'get',
  submitData?: object
) => {
  // instance 默认已经设定好响应的数据类型, 如果想要自定义,传入泛型
  // instance 实例的第二个泛型, 可以强制规定响应数据的结构
  return instance<T, ResponseData<T>>({
    url,
    method,
    // params: submitData
    // data: submitData
    // 这里可以用中括号的方式指定动态的 key 键名
    [method.toLowerCase() === 'get' ? 'params' : 'data']: submitData
  })
}

// 暴露实例
export { baseURL, instance, request }
